import appConst from './const';
export default class Utils {
  public static abp = window.abp;

  public static setToken(authToken: string, expireDate: Date | undefined) {
    Utils.setCookieValue(appConst.tokenCookieName, authToken, expireDate, Utils.abp.appPath, Utils.abp.domain)
  }
  public static getToken() {
    return Utils.getCookieValue(appConst.tokenCookieName)
  }
  public static clearToken() {
    Utils.deleteCookie(appConst.tokenCookieName, Utils.abp.appPath)
  }

  public static setRefreshToken(refreshToken: string, expireDate: Date) {
    Utils.setCookieValue(appConst.refreshTokenCookieName, refreshToken, expireDate, Utils.abp.appPath, Utils.abp.domain);
  }

  public static getRefreshToken() {
    return Utils.getCookieValue(appConst.refreshTokenCookieName)
  }

  public static clearRefreshToken() {
    Utils.deleteCookie(appConst.refreshTokenCookieName, Utils.abp.appPath)

  }


  public static getCultureName() {
    return Utils.getCookieValue(appConst.cultureName);
  }



  public static setTenantIdCookie(tenantId: string) {
    if (tenantId) {
      Utils.setCookieValue(
        appConst.tenantIdCookieName,
        tenantId.toString(),
        new Date(new Date().getTime() + 5 * 365 * 86400000), //5 years
        Utils.abp.appPath,
        Utils.abp.domain
      );
    } else {
      Utils.deleteCookie(appConst.tenantIdCookieName, Utils.abp.appPath);
    }
  }

  public static getTenantIdCookie() {
    const value = Utils.getCookieValue(appConst.tenantIdCookieName);
    if (!value) {
      return null;
    }

    return parseInt(value);
  }
  public static setCookieValueS(key: string, value: string) {
    Utils.setCookieValue(key, value, undefined, "", "");
  }
  /**
     * Sets a cookie value for given key.
     * This is a simple implementation created to be used by ABP.
     * Please use a complete cookie library if you need.
     * @param {string} key
     * @param {string} value 
     * @param {Date} expireDate (optional). If not specified the cookie will expire at the end of session.
     * @param {string} path (optional)
     */
  public static setCookieValue(key: string, value: string, expireDate: Date | undefined, path: string, domain: string) {
    let cookieValue = encodeURIComponent(key) + '=';

    if (value) {
      cookieValue = cookieValue + encodeURIComponent(value);
    }

    if (expireDate) {
      cookieValue = cookieValue + "; expires=" + expireDate.toUTCString();
    }

    if (path) {
      cookieValue = cookieValue + "; path=" + path;
    }

    if (domain) {
      cookieValue = cookieValue + "; domain=" + domain;
    }

    document.cookie = cookieValue;
  }

  /**
   * Gets a cookie with given key.
   * This is a simple implementation created to be used by ABP.
   * Please use a complete cookie library if you need.
   * @param {string} key
   * @returns {string} Cookie value or null
   */
  public static getCookieValue(key: string) {
    const equalities = document.cookie.split('; ');
    for (let i = 0; i < equalities.length; i++) {
      if (!equalities[i]) {
        continue;
      }

      const splitted = equalities[i].split('=');
      if (splitted.length != 2) {
        continue;
      }

      if (decodeURIComponent(splitted[0]) === key) {
        return decodeURIComponent(splitted[1] || '');
      }
    }

    return null;
  }

  /**
   * Deletes cookie for given key.
   * This is a simple implementation created to be used by ABP.
   * Please use a complete cookie library if you need.
   * @param {string} key
   * @param {string} path (optional)
   */
  public static deleteCookie(key: string, path: string) {
    let cookieValue = encodeURIComponent(key) + '=';

    cookieValue = cookieValue + "; expires=" + (new Date(new Date().getTime() - 86400000)).toUTCString();

    if (path) {
      cookieValue = cookieValue + "; path=" + path;
    }

    document.cookie = cookieValue;
  }

  public static localize(key: string, sourceName: string): string {
    if (Utils.abp && Utils.abp.localization) {

      sourceName = sourceName || Utils.abp.localization.defaultSourceName;     
      const source = Utils.abp.localization.values[sourceName];

      if (!source) {
        console.warn('Could not find localization source: ' + sourceName);
        return key;
      }

      const value = source[key];
      if (value == undefined) {
        return key;
      }
      return value;
    }
    return key;

    /* var copiedArguments = Array.prototype.slice.call(, 0);
    copiedArguments.splice(1, 1);
    copiedArguments[0] = value;

    return abp.utils.formatString.apply(this, copiedArguments); */
  }

  /*   public static getSource(sourceName: string): (key: string) => string {
      const that = this;
      return function (key) {
        var copiedArguments = Array.prototype.slice.call(arguments, 0);
        copiedArguments.splice(1, 0, sourceName);
        return Utils.abp.localization.localize.apply(that, copiedArguments);
      };
    } */

  public static isCurrentCulture(name: string): boolean {
    if (Utils.abp.localization.currentLanguage) {
      if (Utils.abp.localization.currentLanguage.name) {
        if (Utils.abp.localization.currentLanguage.name.indexOf(name) == 0) {
          return true;
        }
      }
    }

    return false;
  }


  public static title(title: string) {
    const appname = Utils.localize('AppName', appConst.localization.defaultLocalizationSourceName);
    const page = Utils.localize(title, appConst.localization.defaultLocalizationSourceName);
    window.document.title = appname + '--' + page;
  }

  public static getRouterObjByName(routers: Array<any>, name: string | null | undefined): any {
    if (!name || !routers || !routers.length) {
      return null;
    }
    // debugger;
    let routerObj = null;
    for (const item of routers) {
      if (item.name === name) {
        return item;
      }
      routerObj = this.getRouterObjByName(item.children, name);
      if (routerObj) {
        return routerObj;
      }
    }
    return null;
  }
  public static toDefaultPage(routers: Array<any>, name: string | null | undefined, route: any, next: any) {
    const len = routers.length;
    let i = 0;
    let notHandle = true;
    while (i < len) {
      if (routers[i].name === name && routers[i].children && routers[i].redirect === undefined) {
        route.replace({
          name: routers[i].children[0].name
        });
        notHandle = false;
        next();
        break;
      }
      i++;
    }
    if (notHandle) {
      next();
    }
  }
  public static handleTitle(vm: any, item: any) {
    if (typeof item.meta.title === 'object') {
      return vm.$t(item.title.i18n);
    } else {
      return item.meta.title;
    }
  }
  public static setCurrentPath(vm: Vue, name?: string) {
    let title = '';
    let isOtherRouter = false;
    vm.$store.state.app.routers.forEach((item: any) => {
      if (item.children.length === 1) {
        if (item.children[0].name === name) {
          title = Utils.handleTitle(vm, item);
          if (item.name === 'otherRouter') {
            isOtherRouter = true;
          }
        }
      } else {
        item.children.forEach((child: any) => {
          if (child.name === name) {
            title = this.handleTitle(vm, child);
            if (item.name === 'otherRouter') {
              isOtherRouter = true;
            }
          }
        });
      }
    });
    let currentPathArr = [];
    if (name === 'home') {
      currentPathArr = [
        {
          meta: { title: Utils.handleTitle(vm, Utils.getRouterObjByName(vm.$store.state.app.routers, 'home')) },
          path: 'main/home',
          name: 'home'
        }
      ];
    } else if (((name as string).indexOf('index') >= 0 || isOtherRouter) && name !== 'home') {
      currentPathArr = [
        {
          meta: { title: Utils.handleTitle(vm, Utils.getRouterObjByName(vm.$store.state.app.routers, 'home')) },
          path: 'main/home',
          name: 'home'
        },
        {
          meta: { title: title },
          path: '',
          name: name
        }
      ];
    } else {
      const currentPathObj = vm.$store.state.app.routers.filter((item: any) => {
        if (item.children.length <= 1) {
          return item.children[0].name === name || item.name === name;
        } else {
          let i = 0;
          const childArr = item.children;
          const len = childArr.length;
          while (i < len) {
            if (childArr[i].name === name) {
              return true;
            }
            i++;
          }
          return false;
        }
      })[0];
      if (currentPathObj.children && currentPathObj.children.length <= 1 && currentPathObj.name === 'home') {
        currentPathArr = [
          {
            meta: { title: 'HomePage' },
            path: 'main/home',
            name: 'home'
          }
        ];
      } else if (currentPathObj.children && currentPathObj.children.length <= 1 && currentPathObj.name !== 'home') {
        currentPathArr = [
          {
            meta: { title: 'HomePage' },
            path: 'main/home',
            name: 'home'
          },
          {
            meta: { title: currentPathObj.meta.title },
            path: '',
            name: name
          }
        ];
      } else {
        const childObj = currentPathObj.children.filter((child: any) => {
          return child.name === name;
        })[0];
        currentPathArr = [
          {
            meta: { title: 'HomePage' },
            path: 'main/home',
            name: 'home'
          },
          {
            meta: { title: currentPathObj.meta.title },
            path: '',
            name: ''
          },
          {
            meta: { title: childObj.meta.title },
            path: currentPathObj.path + '/' + childObj.path,
            name: name
          }
        ];
      }
    }
    vm.$store.commit('app/setCurrentPath', currentPathArr);

    return currentPathArr;
  }

  public static openNewPage(vm: Vue, name: string | null | undefined, argu?: any, query?: any) {
    console.info(vm);
    console.info("vm.$store.state");
    console.info(vm.$store.state);
    const pageOpenedList = vm.$store.state.app.pageOpenedList;
    const openedPageLen = pageOpenedList.length;
    let i = 0;
    let tagHasOpened = false;
    while (i < openedPageLen) {
      if (name === pageOpenedList[i].name) { // 页面已经打开
        vm.$store.commit('app/pageOpenedList', {
          index: i,
          argu: argu,
          query: query
        });
        tagHasOpened = true;
        break;
      }
      i++;
    }
    if (!tagHasOpened) {
      let tag = vm.$store.state.app.tagsList.filter((item: any) => {
        if (item.children) {
          return name === item.children[0].name;
        } else {
          return name === item.name;
        }
      });
      tag = tag[0];
      if (tag) {
        tag = tag.children ? tag.children[0] : tag;
        if (argu) {
          tag.argu = argu;
        }
        if (query) {
          tag.query = query;
        }
        vm.$store.commit('app/increateTag', tag);
      }
    }
    vm.$store.commit('app/setCurrentPageName', name);
  }


  public static hasPermission(permissionName: any) {
    return Utils.isGranted.apply(this, permissionName)
  }
  public static hasAnyOfPermissions(args: Array<string>) {
    return Utils.isAnyGranted(args)
  }

  //Deprecated. Use abp.auth.areAllGranted instead.
  public static hasAllOfPermissions(args: Array<string>) {

    return Utils.areAllGranted(args);
  }
  public static isGranted(permissionName: string) {
    return Utils.abp.auth.allPermissions[permissionName] != undefined &&
      Utils.abp.auth.grantedPermissions[permissionName] != undefined
  }
  public static isAnyGranted(args: Array<string>) {
    if (!args || args.length <= 0) {
      return true;
    }

    for (let i = 0; i < args.length; i++) {
      if (Utils.isGranted(args[i])) {
        return true;
      }
    }

    return false;
  }

  public static areAllGranted(args: Array<string>) {
    if (!args || args.length <= 0) {
      return true;
    }

    for (let i = 0; i < args.length; i++) {
      if (!Utils.isGranted(args[i])) {
        return false;
      }
    }

    return true;
  }



  public static inOf(arr: Array<any>, targetArr: any) {
    let res = true;
    arr.forEach(item => {
      if (targetArr.indexOf(item) < 0) {
        res = false;
      }
    });
    return res;
  }
  public static oneOf(ele: any, targetArr: Array<any>) {
    if (targetArr.indexOf(ele) >= 0) {
      return true;
    } else {
      return false;
    }
  }

  public static extend(...args: any[]) {
    let options, name, src, srcType, copy, copyType, copyIsArray, clone,
      target = args[0] || {},
      i = 1,
      deep = false;
    const length = args.length
    if (typeof target === 'boolean') {
      deep = target;
      target = args[i] || {};
      i++;
    }
    if (typeof target !== 'object' && typeof target !== 'function') {
      target = {};
    }
    if (i === length) {
      target = this;
      i--;
    }
    for (; i < length; i++) {
      if ((options = args[i]) !== null) {
        for (name in options) {
          src = target[name];
          copy = options[name];
          if (target === copy) {
            continue;
          }
          srcType = Array.isArray(src) ? 'array' : typeof src;
          if (deep && copy && ((copyIsArray = Array.isArray(copy)) || typeof copy === 'object')) {
            if (copyIsArray) {
              copyIsArray = false;
              clone = src && srcType === 'array' ? src : [];
            } else {
              clone = src && srcType === 'object' ? src : {};
            }
            target[name] = this.extend(deep, clone, copy);
          } else if (copy !== undefined) {
            target[name] = copy;
          }
        }
      }
    }
    return target;
  }
}
